package bd;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import negocios.Convite;
import negocios.Localizador;
import negocios.LocalizadorIP;
import negocios.LocalizadorManual;
import negocios.Mensagem;
import negocios.MensagemTexto;
import negocios.Relacionamento;
import negocios.SMS;
import negocios.Usuario;
import negocios.UsuarioComum;
import negocios.excecoes.EntradaInvalidaException;
import negocios.excecoes.LocalizacaoException;

import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import bd.excecoes.XMLException;

/**
 * Classe que gera objetos do pacote de negocios, a partir de elementos do XML.
 * 
 * @author Jonathan Brilhante
 * @author Jose Rafael
 * @author Nata Venancio
 * @author Renato Almeida
 * 
 * @version 2.0
 */

public class GeraObjetos {
	private Document doc;

	/**
	 * Cria um gerador de objetos, a partir do documento passado como parametro
	 * 
	 * @param doc
	 *            o documento
	 */
	public GeraObjetos(Document doc) {
		this.doc = doc;
	}

	/**
	 * Seta um objeto do tipo Doc.
	 * 
	 * @param doc
	 */
	public void setDoc(Document doc) {
		this.doc = doc;
	}

	/**
	 * Cria uma lista de Relacionamentos a partir de um elemento Amigo passado
	 * como parametro.
	 * 
	 * @param amigo
	 *            o elemento amigo
	 * @return retorna uma lista de Relacionamentos
	 * @throws DOMException
	 * @throws IOException
	 */
	private List<Relacionamento> criarObjetoListaAmigos(Element amigo)
			throws DOMException, IOException {
		ArrayList<Relacionamento> amigosAux = new ArrayList<Relacionamento>();
		NodeList amigos = amigo.getElementsByTagName("amigo");
		for (int i = 0; i < amigos.getLength(); i++) {
			amigosAux.add(criarObjetoAmigo((Element) amigos.item(i)));
		}
		return amigosAux;
	}

	/**
	 * Cria um objeto Usuario a partir de um elemento usuario do documento XML.
	 * 
	 * @param usuario
	 *            o elemento usuario
	 * @return o objeto Usuario
	 * @throws DOMException
	 * @throws IOException
	 */
	public Usuario criarObjetoUsuario(Element usuario) throws DOMException,
			IOException {
		Usuario usuarioObjeto = null;
		try {
			usuarioObjeto = new UsuarioComum(usuario.getAttributeNode(
					"username").getNodeValue(), usuario.getElementsByTagName(
					"nome").item(0).getTextContent(), usuario
					.getElementsByTagName("email").item(0).getTextContent(),
					usuario.getAttributeNode("senha").getNodeValue(), usuario
							.getElementsByTagName("telefone").item(0)
							.getTextContent());
		} catch (EntradaInvalidaException e1) {
			e1.printStackTrace();
		}
		List<Relacionamento> amigos = criarObjetoListaAmigos((Element) usuario
				.getElementsByTagName("amigos").item(0));
		for (Relacionamento amigo : amigos) {
			try {
				usuarioObjeto.adicionaAmigo(amigo.getAmigo());
			} catch (EntradaInvalidaException e) {
				e.printStackTrace();
			}
		}
		Element caixaPostal = (Element) usuario.getElementsByTagName(
				"caixapostal").item(0);
		NodeList mensagens = ((Element) caixaPostal.getElementsByTagName(
				"mensagens").item(0)).getElementsByTagName("mensagem");
		for (int i = 0; i < mensagens.getLength(); i++) {
			Mensagem mensagem = criarObjetoMensagem((Element) mensagens.item(i));
			usuarioObjeto.getCaixaPostal().inserir(mensagem);
		}

		Element localizador = (Element) usuario.getElementsByTagName(
				"localizador").item(0);
		String tipo = localizador.getElementsByTagName("tipo").item(0)
				.getTextContent();
		Localizador loc = null;
		try {
			if (tipo.endsWith(GeraElementosXML.IP)) {
				String ip = localizador.getElementsByTagName("ip").item(0)
						.getTextContent();
				loc = new LocalizadorIP(ip);
			} else if (tipo.endsWith(GeraElementosXML.MANUAL)) {
				double lat = Double.parseDouble(localizador
						.getElementsByTagName("latitude").item(0)
						.getTextContent());
				double longi = Double.parseDouble(localizador
						.getElementsByTagName("longitude").item(0)
						.getTextContent());
				loc = new LocalizadorManual(lat, longi);
			}
		} catch (LocalizacaoException e) {
			throw new XMLException("Problema ao ler localizador");
		}
		usuarioObjeto.setLocalizador(loc);
		return usuarioObjeto;
	}

	/**
	 * Cria um objeto Date, a partir de um Elemento data.
	 * 
	 * @param data
	 *            o elemento data
	 * @return o objeto Date
	 */
	@SuppressWarnings("deprecation")
	private Date criarObjetoDate(Element data) {
		Date dataObjeto = new Date();
		dataObjeto.setMonth(Integer.parseInt(data.getAttributeNode("mes")
				.getValue()) + 1);
		dataObjeto.setYear(Integer.parseInt(data.getAttributeNode("ano")
				.getValue()) + 1900);
		dataObjeto.setDate(Integer.parseInt(data.getAttributeNode("dia")
				.getValue()));
		return dataObjeto;
	}

	/**
	 * Este metodo verifica no banco de dados se ja existe um username, passado
	 * como parametro.
	 * 
	 * @param username
	 *            o username passado como parametro
	 * @return o elemento, caso exista.
	 */
	private Element getUsuario(String username) {
		Element raiz = doc.getDocumentElement();
		NodeList usuarios = raiz.getElementsByTagName("usuario");
		for (int i = 0; i < usuarios.getLength(); i++) {
			Element usuarioAuxiliar = (Element) usuarios.item(i);
			Attr usernameAux = usuarioAuxiliar.getAttributeNode("username");
			if (usernameAux.getValue().equals(username)) {
				return usuarioAuxiliar;
			}
		}
		return null;
	}

	/**
	 * Cria um objeto Relacionamento, a partir de um elemento (Amigo) passado
	 * como parametro.
	 * 
	 * @param amigo
	 *            o elemento amigo.
	 * @return um objeto Relacionamento.
	 * @throws DOMException
	 * @throws EntradaInvalidaException
	 * @throws IOException
	 */
	private Relacionamento criarObjetoAmigo(Element amigo) throws DOMException,
			IOException {
		Usuario usuarioAux = criarObjetoUsuario(getUsuario(amigo
				.getElementsByTagName("username").item(0).getTextContent()));
		Relacionamento amigoAux = new Relacionamento(usuarioAux, amigo
				.getElementsByTagName("meuusername").item(0).getTextContent());
		if (amigo.getAttributeNode("ocultar").getNodeValue().equals("true")) {
			amigoAux.ocultar();
		}
		return amigoAux;
	}

	/**
	 * Cria uma Mensagem a partir de um elemento Mensagem.
	 * 
	 * @param mensagem
	 * @return a mensagem criada
	 * @throws DOMException
	 * @throws EntradaInvalidaException
	 * @throws IOException
	 * @throws LocalizacaoException
	 */
	private Mensagem criarObjetoMensagem(Element mensagem) throws DOMException,
			IOException {
		Mensagem mensagemObjeto = null;
		String conteudo = "conteudo";
		String assunto = "assunto";
		String remetente = mensagem.getElementsByTagName("remetente").item(0)
				.getTextContent();
		String destinatario = mensagem.getElementsByTagName("destinatario")
				.item(0).getTextContent();
		if (!mensagem.getAttributeNode("tipo").getNodeValue().endsWith(
				GeraElementosXML.CONVITE)) {
			conteudo = mensagem.getElementsByTagName("conteudo").item(0)
					.getTextContent();
			assunto = mensagem.getElementsByTagName("assunto").item(0)
					.getTextContent();
		}
		Date data = criarObjetoDate((Element) mensagem.getElementsByTagName(
				"data").item(0));
		if (mensagem.getAttributeNode("tipo").getNodeValue().endsWith(
				GeraElementosXML.CONVITE)) {
			String email = mensagem.getElementsByTagName("email").item(0)
					.getTextContent();
			mensagemObjeto = new Convite(remetente, email, destinatario, data);
			return mensagemObjeto;
		}
		if (mensagem.getAttributeNode("tipo").getNodeValue().endsWith(
				GeraElementosXML.MENSAGEM_TEXTO)) {
			mensagemObjeto = new MensagemTexto(remetente, destinatario,
					assunto, conteudo, data);
			return mensagemObjeto;
		}
		if (mensagem.getAttributeNode("tipo").getNodeValue().endsWith(
				GeraElementosXML.SMS)) {
			try {
				mensagemObjeto = new SMS(remetente, destinatario, conteudo,
						data);
			} catch (EntradaInvalidaException e) {
				e.printStackTrace();
			}
			return mensagemObjeto;
		}
		return null;
	}
}